package com.css.crm.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;

import javax.el.ELContext;
import javax.el.ELResolver;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import com.css.crm.exception.SystemException;
import com.css.crm.message.SystemErrorMessage;
import com.css.crm.service.LdapService;
import com.css.crm.service.SystemService;
import com.css.crm.service.impl.LdapServiceImpl;
import com.css.crm.service.impl.SystemServiceImpl;
import com.css.crm.utility.ConstantUtil;
import com.css.crm.utility.SystemUtil;
import com.css.crm.vo.AbstractObjectPermission;
import com.css.crm.vo.AbstractUser;
import com.css.crm.vo.MenuMap;
import com.css.crm.vo.PermissionCollection;
import com.css.crm.vo.User;
import com.css.crm.vo.UserManager;
import com.css.db.MyBatisConfig;

@ManagedBean(name = "loginBean")
@SessionScoped
public class LoginBean implements Serializable {

	private static final long serialVersionUID = 1L;

	private static final Logger log = Logger.getLogger(LoginBean.class);

	public static final String LOGIN_FAILED = ConstantUtil.PAGE_LOGIN;
	public static final String LOGIN_PASSED = "mainMenu";
	public static final String LOGOUT = "logout";
	private LdapService ldapService = new LdapServiceImpl();

	public LoginBean() {
	}

	public String login() {

		FacesContext fc = FacesContext.getCurrentInstance();
		ELContext elContext = fc.getELContext();
		ELResolver elResolver = fc.getApplication().getELResolver();
		AbstractUser user = (AbstractUser) elResolver.getValue(elContext, null, ConstantUtil.SESSION_USER_KEY);
		SqlSession sqlSession = null;

		try {
			if (user == null) {
				user = new User();
			}
			HttpServletRequest req = (HttpServletRequest) fc.getExternalContext().getRequest();
			log.info(user.getSessionId() + "|" + user.getId() + "|perform login - start IP: " + req.getRemoteAddr());

			boolean passed = ldapService.authenticate(user);
			user.setPassword(null);

			if (passed) {
				user.setSessionId(req.getRequestedSessionId());
				sqlSession = MyBatisConfig.getSession();
				SystemService systemService = new SystemServiceImpl();
				systemService.setSession(sqlSession);

				ArrayList<User> users = (ArrayList<User>) systemService.getApplAccount(user.getId(), ConstantUtil.APPLICATION_ID);
				if (users == null || users.size() != 1) {
					throw new SystemException(SystemErrorMessage.LDAP_AUTHENTICATE_FAILURE);
				}

				user = users.get(0);
				user.setSessionId(req.getRequestedSessionId());
				user.setIpAddress(req.getRemoteAddr());
				user.setEmailAddress(ldapService.emailLookup(user.getId()));
				user.setCustodianUnitCode(systemService.getAccountDefaultUnit(user.getId(), ConstantUtil.APPLICATION_ID));
				user.setSingleCustodianUnitCode(systemService.getAccountSingleUnit(user.getId(), ConstantUtil.APPLICATION_ID));
				user.setUnitCodes(systemService.getAccountUnits(user.getId(), ConstantUtil.APPLICATION_ID));

				// get sm user id by ldap id
				user.setSmUserId(systemService.getUserIdByLdapId(user.getId(), user.getCustodianUnitCode()));
				if (user.getUnitCodes() == null) {
					throw new SystemException(SystemErrorMessage.NO_CUSD_UNIT_CODE);
				}

				SystemUtil.saveSession(ConstantUtil.SESSION_USER_KEY, user);

				// 2. Collect all granted permission of the user and assign to
				// session map of current Faces Context Instance
				PermissionCollection pc = (PermissionCollection) fc.getApplication().getELResolver().getValue(fc.getELContext(), null, "permissionCollection");
				if (pc == null) {
					pc = new PermissionCollection();
				}
				pc.setPermissionList(systemService.getAllObjectPermission(user.getId(), ConstantUtil.APPLICATION_ID));
				log.debug(pc.getPermissionList().size() + " Permission records loaded");
				fc.getExternalContext().getSessionMap().put("permissionCollection", pc);

				if (pc.getPermissionList().size() == 0) {
					throw new SystemException(SystemErrorMessage.NO_ACCESS_RIGHT);
				}

				AbstractObjectPermission p = pc.getPermission(MenuMap.menuMapInstance.getRtmuId());
				if (p == null || (!p.isReadable() && !p.isWritable())) {
					throw new SystemException(SystemErrorMessage.NO_READ_RIGHT);
				}

				MenuBean menuBean = (MenuBean) elResolver.getValue(elContext, null, "menuBean");
				menuBean.setCurrentMenuItemId(MenuMap.menuMapInstance.getRtmuId());
				log.info(user.getSessionId() + "|" + user.getId() + "|perform login - successful\n" + user);

				return LOGIN_PASSED;
			} else {
				throw new SystemException(SystemErrorMessage.LDAP_AUTHENTICATE_ERROR);
			}
		} catch (SystemException e) {
			FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_FATAL, e.getNewSystemMessage(), null);
			fc.addMessage(null, message);

			return "";
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}

	/*
	 * public PermissionCollection updatePermissionConnection(FacesContext fc,
	 * SystemService systemService, String accountId, String applId, String
	 * type, String objectId, String parentObjectId) { ELContext elContext =
	 * fc.getELContext(); ELResolver elResolver =
	 * fc.getApplication().getELResolver(); PermissionCollection pc =
	 * (PermissionCollection) elResolver.getValue(elContext, null,
	 * "permissionCollection"); try { if (pc == null) { pc = new
	 * PermissionCollection(); }
	 * 
	 * //Modified by Lawrence on 20110705 //Get all permission for the user
	 * //pc.setPermissionList(systemService.getObjectPermission(accountId,
	 * applId, type, objectId, parentObjectId));
	 * pc.setPermissionList(systemService.getAllObjectPermission(accountId,
	 * applId));
	 * 
	 * log.debug(pc.getPermissionList().size() + " Permission records loaded");
	 * fc.getExternalContext().getSessionMap().put("permissionCollection", pc);
	 * } catch (SystemException e) { FacesContext context =
	 * FacesContext.getCurrentInstance(); FacesMessage message = null; message =
	 * new FacesMessage(FacesMessage.SEVERITY_FATAL, e.getNewSystemMessage(),
	 * null); context.addMessage(null, message);
	 * log.error("Update permission connection error occurred.", e); } return
	 * pc; }
	 */
	public String logout() {
		ELContext elContext = FacesContext.getCurrentInstance().getELContext();
		ELResolver elResolver = FacesContext.getCurrentInstance().getApplication().getELResolver();
		AbstractUser user = (AbstractUser) elResolver.getValue(elContext, null, "user");
		log.info(user.getSessionId() + "|" + user.getId() + "|perform logout - start\n" + user);

		UserManager userManager = (UserManager) elResolver.getValue(elContext, null, UserManager.BEAN_NAME);
		if (userManager != null) {
			userManager.removeActiveTrack(user);
		}

		Map<String, Object> beans = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
		Object[] s = beans.keySet().toArray();
		for (int i = 0; i < s.length; i++) {
			FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(s[i]);
		}
		log.info(user.getSessionId() + "|" + user.getId() + "|perform logout - end\n");
		return LOGOUT;
	}
}
